<?php

    /**
     * @package      Barcode
     * @subpackage   Adapter
     *
     * @license      GNU Lesser General Public Licence see LICENCE-LGPL file or http://www.gnu.org/licenses/lgpl.html
     */
    class Barcode_Adapter_Ean13 extends Barcode_Adapter_Abstract
    {

    ////////////////////////////////////////////////////////////////////////////
    //                              Methods                                   //
    ////////////////////////////////////////////////////////////////////////////

        /**
         * Constructor
         */
        public function __construct()
        {
            /*
             * Defines path
             */
            $this->_path = Core_IO_Path::combine(
                                                    PROJECT_TEMP_PATH,
                                                    'barcodes',
                                                    'ean13'
                                                );

            if (!Core_IO_Directory::exists($this->_path)) {
                Core_IO_Directory::createDirectory($this->_path);
            }

            /*
             * Coding map
             */
            $this->_codingMap = array('0' => array(
                                                'A' => array(0,0,0,1,1,0,1),
                                                'B' => array(0,1,0,0,1,1,1),
                                                'C' => array(1,1,1,0,0,1,0)
                                                    ),
                                       '1' => array(
                                                'A' => array(0,0,1,1,0,0,1),
                                                'B' => array(0,1,1,0,0,1,1),
                                                'C' => array(1,1,0,0,1,1,0)
                                                    ),
                                       '2' => array(
                                                'A' => array(0,0,1,0,0,1,1),
                                                'B' => array(0,0,1,1,0,1,1),
                                                'C' => array(1,1,0,1,1,0,0)
                                                    ),
                                       '3' => array(
                                                'A' => array(0,1,1,1,1,0,1),
                                                'B' => array(0,1,0,0,0,0,1),
                                                'C' => array(1,0,0,0,0,1,0)
                                                    ),
                                       '4' => array(
                                                'A' => array(0,1,0,0,0,1,1),
                                                'B' => array(0,0,1,1,1,0,1),
                                                'C' => array(1,0,1,1,1,0,0)
                                                    ),
                                       '5' => array(
                                                'A' => array(0,1,1,0,0,0,1),
                                                'B' => array(0,1,1,1,0,0,1),
                                                'C' => array(1,0,0,1,1,1,0)
                                                    ),
                                       '6' => array(
                                                'A' => array(0,1,0,1,1,1,1),
                                                'B' => array(0,0,0,0,1,0,1),
                                                'C' => array(1,0,1,0,0,0,0)
                                                    ),
                                       '7' => array(
                                                'A' => array(0,1,1,1,0,1,1),
                                                'B' => array(0,0,1,0,0,0,1),
                                                'C' => array(1,0,0,0,1,0,0)
                                                    ),
                                       '8' => array(
                                                'A' => array(0,1,1,0,1,1,1),
                                                'B' => array(0,0,0,1,0,0,1),
                                                'C' => array(1,0,0,1,0,0,0)
                                                    ),
                                       '9' => array(
                                                'A' => array(0,0,0,1,0,1,1),
                                                'B' => array(0,0,1,0,1,1,1),
                                                'C' => array(1,1,1,0,1,0,0)
                                                    )
                                        );

            $this->_codingMapLeftCoding = array(
                                               '0' => array('A','A','A','A','A','A'),
                                               '1' => array('A','A','B','A','B','B'),
                                               '2' => array('A','A','B','B','A','B'),
                                               '3' => array('A','A','B','B','B','A'),
                                               '4' => array('A','B','A','A','B','B'),
                                               '5' => array('A','B','B','A','A','B'),
                                               '6' => array('A','B','B','B','A','A'),
                                               '7' => array('A','B','A','B','A','B'),
                                               '8' => array('A','B','A','B','B','A'),
                                               '9' => array('A','B','B','A','B','A')
                                              );
        }

        /**
         * Creates the barcode image.
         *
         * @param       int                 $value
         * @throws      Core_Exception
         * @return      string              Image path
         */
        public function process($value)
        {
            if (!is_numeric($value) || strlen($value) != 13) {
                throw new Core_Exception('Fatal error : EAN-13 only accepts 13 numeric digits!');
            }

            $cacheFile = Core_IO_Path::combine($this->_path, $value . '.png');

            if (Core_IO_File::exists($cacheFile)) {
                // If barcode is still in cache return its path
                return $cacheFile;
            }

            /*
             * Calculate the barcode width
             */
            $barcodewidth = (strlen($value)) * (7 * $this->_barWidth)
            + 3 // left
            + 5 // center
            + 3 // right
            + ImageFontWidth($this->_fontSize) + 1;

            $fontHeight = ImageFontHeight($this->_fontSize);
            $fontWidth  = ImageFontWidth($this->_fontSize);

            $barcodeLongHeight = (int) ($fontHeight / 2) + $this->_barcodeHeight;

            /*
             * Create the image
             */
            $img = ImageCreate($barcodewidth, $barcodeLongHeight + $fontHeight + 1);

            /*
             * Alocate the black and white colors
             */
            $black = ImageColorAllocate($img, 0, 0, 0);
            $white = ImageColorAllocate($img, 255, 255, 255);

            /*
             * Fill image with white color
             */
            ImageFill($img, 0, 0, $white);

            /*
             * Get the first digit which is the key for creating the first 6 bars
             */
            $key = substr($value,0,1);

            /*
             * Initiate x position
             */
            $xpos = 0;

            /*
             * Print first digit
             */
            ImageString($img, $this->_fontSize, $xpos, $this->_barcodeHeight, $key, $black);
            $xpos= ImageFontWidth($this->_fontSize) + 1;

            /*
             * Draws the left guard pattern (bar-space-bar) bar
             */
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;
            $xpos += $this->_barWidth;
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;

            /*
             * Draw left $value contents
             */
            $setArray = $this->_codingMapLeftCoding[$key];

            for ($idx = 1; $idx < 7; $idx ++) {
                $current = substr($value, $idx, 1);
                ImageString ($img, $this->_fontSize, $xpos+1, $this->_barcodeHeight, $current, $black);

                foreach ($this->_codingMap[$current][$setArray[$idx-1]] as $bar) {
                    if ($bar) {
                        ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $this->_barcodeHeight, $black);
                    }
                    $xpos += $this->_barWidth;
                }

            }

            /*
             * Draws the center pattern (space-bar-space-bar-space)
             */
            $xpos += $this->_barWidth;
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;
            $xpos += $this->_barWidth;
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;
            $xpos += $this->_barWidth;

            /*
             * Draw right $value contents
             */
            for ($idx = 7; $idx < 13; $idx ++) {
                $current = substr($value,$idx,1);

                ImageString ($img, $this->_fontSize, $xpos+1, $this->_barcodeHeight, $current, $black);

                foreach ($this->_codingMap[$current]['C'] as $bar) {
                    if ($bar) {
                        ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $this->_barcodeHeight, $black);
                    }
                    $xpos += $this->_barWidth;
                }
            }

            /*
             * Draws the right guard pattern (bar-space-bar)
             */
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;
            $xpos += $this->_barWidth;
            ImageFilledRectangle($img, $xpos, 0, $xpos + $this->_barWidth - 1, $barcodeLongHeight, $black);
            $xpos += $this->_barWidth;

            ImagePNG($img,$cacheFile);
            ImageDestroy($img);

            return $cacheFile;
        }
    }